/**
 * @开发版权 
 * @项目名称 轻量数据中台(LDMP)
 * @版本信息 v1.0
 * @开发人员 zhous
 * @开发日期 2025-01-17
 * @修订日期
 * @描述  AuthController
 */
package com.ng.sys.controller;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import javax.imageio.ImageIO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.FastByteArrayOutputStream;
import org.springframework.web.bind.annotation.*;

import com.alibaba.fastjson.JSONObject;
import com.google.code.kaptcha.Producer;
import com.jfinal.kit.StrKit;
import com.ng.common.constants.SecurityConstants;
import com.ng.common.model.response.R;
import com.ng.common.util.EncryptUtil;
import com.ng.common.util.JwtUtil;
import com.ng.common.util.RsaUtil;
import com.ng.common.util.UuidUtil;
import com.ng.sys.model.domain.User;
import com.ng.sys.model.request.LoginRequest;
import com.ng.sys.model.response.CaptchaResponse;
import com.ng.sys.model.response.LoginResponse;
import com.ng.sys.model.response.RefreshTokenResponse;
import com.ng.sys.service.IUser;
import cn.hutool.core.codec.Base64;
import io.jsonwebtoken.Claims;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Tag(name = "鉴权管理")
@RequiredArgsConstructor
@RestController
@RequestMapping("/sys/auth")
@Slf4j
public class AuthController {

	@Autowired
	private JwtUtil jwtUtil;

	@Autowired
	private Producer producer;

	@Autowired
	private StringRedisTemplate redisTemplate;
	
	@Autowired
	private IUser userImpl;

	@PostMapping("/login")
	@Operation(summary = "登录")
	@Parameters({ @Parameter(name = "authRequest", description = "参数", required = true) })
	public R<LoginResponse> authenticate(@RequestBody LoginRequest loginRequest) throws Exception {

		if (StrKit.isBlank(loginRequest.getCaptchaKey()) || StrKit.isBlank(loginRequest.getCaptchaCode())) {
			return R.failed("验证码必填.");
		}

		String captcha = redisTemplate.opsForValue()
				.get(SecurityConstants.VERIFY_CODE_PREFIX + loginRequest.getCaptchaKey());
		redisTemplate.delete(SecurityConstants.VERIFY_CODE_PREFIX + loginRequest.getCaptchaKey());
		if (StrKit.isBlank(captcha)) {
			return R.failed("验证码已过期.");
		}

		if (!StrKit.equals(captcha, loginRequest.getCaptchaCode())) {
			return R.failed("验证码错误.");
		}

		if (StrKit.isBlank(loginRequest.getPassword()) || StrKit.isBlank(loginRequest.getUsername())) {
			return R.failed("账号密码必填.");
		}

		String username = "";
		String password = "";
		try {
			username = RsaUtil.decrypt(loginRequest.getUsername(), SecurityConstants.PRIVATE_KEY);
			password = RsaUtil.decrypt(loginRequest.getPassword(), SecurityConstants.PRIVATE_KEY);
		} catch (Exception e) {
			throw new Exception("解密登录信息失败", e);
		}

		Optional<User> optional = userImpl.findUserByUsername(username);
		if (!optional.isPresent()) {
			return R.failed("用户名或密码错误.");
		}

		User user = optional.get();
		if (user.getError() >= 6) {
			return R.failed("账号已锁定.");
		}

		if (!EncryptUtil.matches(password, user.getPassword())) {
			user.setError(user.getError() + 1);
			user.update();
			return R.failed("用户名或密码错误.");
		}

		if (StrKit.equals(user.getStatus(), "0")) {
			return R.failed("账号已禁用.");
		}

		if (StrKit.equals(user.getStatus(), "-1")) {
			return R.failed("账号已锁定.");
		}

		if (StrKit.equals(user.getStatus(), "-2")) {
			return R.failed("账号已失效.");
		}

		user.setError(0);
		user.update();

		Map<String, Object> claims = new HashMap<String, Object>();

		claims.put("id", user.getId());
		claims.put("username", user.getUsername());
		claims.put("deptId", user.getDeptId());

		String token = jwtUtil.generateToken(user.getUsername(), claims);
		String refreshToken = jwtUtil.generateRefreshToken(user.getUsername(), claims);
		log.info("Generated JWT for user: {}", loginRequest.getUsername());

		LoginResponse loginResponse = new LoginResponse();
		loginResponse.setId(user.getId());
		loginResponse.setUsername(user.getUsername());
		loginResponse.setName(user.getName());
		loginResponse.setAccessToken(token);
		loginResponse.setRefreshToken(refreshToken);
		loginResponse.setTokenType("Bearer");
		return R.ok(loginResponse);
	}

	@Operation(summary = "退出登录")
	@PostMapping("/logout")
	public R<String> logout() {
		return R.ok("成功.");
	}

	@Operation(summary = "刷新Token")
	@PostMapping("/refresh-token")
	public R<RefreshTokenResponse> refreshToken(@RequestBody String refreshToken) {
		
		JSONObject jsonObject=JSONObject.parseObject(refreshToken);
		if(jsonObject!=null) {
			String refreshTokenInfo=jsonObject.getString("refreshToken");
			if (refreshTokenInfo != null && refreshTokenInfo.startsWith("Bearer ")) {
				String token = refreshTokenInfo.substring(7);
				String username = jwtUtil.extractUsername(token);
				Claims claims=jwtUtil.extractAllClaims(token);
				if (username != null && claims!=null && jwtUtil.validateToken(token, username)) {
					Map<String, Object> claimsMap = new HashMap<String, Object>();
					claims.put("id", claims.get("id"));
					claims.put("username", claims.get("username"));
					claims.put("deptId",  claims.get("deptId"));
					RefreshTokenResponse refreshTokenResponse=new RefreshTokenResponse();
					refreshTokenResponse.setAccessToken(jwtUtil.generateToken(username, claimsMap));
					refreshTokenResponse.setRefreshToken(jwtUtil.generateRefreshToken(username, claimsMap));
					refreshTokenResponse.setTokenType("Bearer");
					return R.ok(refreshTokenResponse);
				}
			}
		}
		throw new RuntimeException("Invalid refresh token");
	}

	@Operation(summary = "生成验证码")
	@GetMapping("/captcha")
	public R<CaptchaResponse> getCode(HttpServletResponse response) throws IOException {
		// 保存验证码信息
		String uuid = UuidUtil.getUUID();
		String verifyKey = SecurityConstants.VERIFY_CODE_PREFIX + uuid;
		String capStr = null, code = null;
		BufferedImage image = null;

		String capText = producer.createText();
		capStr = capText.substring(0, capText.lastIndexOf("@"));
		code = capText.substring(capText.lastIndexOf("@") + 1);
		image = producer.createImage(capStr);

		// 将验证码存储到 Redis 中，设置过期时间为60秒
		redisTemplate.opsForValue().set(verifyKey, code, SecurityConstants.ERIFY_CODE_EXPIRATION_TIME,
				TimeUnit.SECONDS);

		FastByteArrayOutputStream os = new FastByteArrayOutputStream();
		try {
			ImageIO.write(image, "jpg", os);
		} catch (IOException e) {
			return R.failed(e.getMessage());
		}
		CaptchaResponse captcha = new CaptchaResponse();
		captcha.setCaptchaKey(uuid);
		captcha.setCaptchaBase64(Base64.encode(os.toByteArray()));
		return R.ok(captcha);
	}

}